﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using Flurl;
using Newtonsoft.Json;
using WebSocket4Net;
using ZilLion.Core.ConfigManager.Manager;
using ZilLion.Core.Unities.UnitiesMethods;
using ZilLion.TaskManager.Core.Command;
using ZilLion.TaskManager.Entity;
using ZilLion.TaskManager.Entity.Config;
using ZilLion.TaskManager.Entity.Entity;
using ZilLion.TaskManager.Entity.SokectMessage;
using ZilLion.TaskManager.Repository;
using WebSocket = WebSocket4Net.WebSocket;

namespace ZilLion.TaskManager.Core.Infrastructure
{
    /// <summary>
    ///     命令监听
    /// </summary>
    public class CommandReceiver
    {
        private static readonly TaskStateRespository TaskStateRespository = new TaskStateRespository();
        private static readonly TaskCommandRespository TaskCommandRespository = new TaskCommandRespository();
        private static WebSocket _currengWebsocket;


        private static void InitSocketClient()
        {
            var url = Url.Combine(TaskManagerGlobalSetting.GetInstance().ManagerServiceHost, "Api",
                "Jwt",
                "GetJwt", "websocket"
            );
            var token = HttpHelper.HttpRequestPost<Dictionary<string, string>, TokenResponse>(url,
                new Dictionary<string, string>
                {
                    {
                        "clinetKey", JsonConvert.SerializeObject(new SocketKeyDto
                        {
                            ClientNo = ZilLionConfigurationManager
                                .GetConfigInstance<TaskManagerCommonConfig>().ClientNo,
                            ClientType = "Workstation"
                        })
                    }
                });


            if (token?.Token.IsNotNullOrEmpty() ?? false)
            {
                var sockethost =
                    Url.Combine(TaskManagerGlobalSetting.GetInstance().ManagerServiceHost, "websocket", "TaskPlatform")
                        .ToLower().Replace("http:", "ws:").Replace("https:", "ws:");
                _currengWebsocket = new WebSocket($"{sockethost}?token={token?.Token}");
                _currengWebsocket.Opened += (s, arg) => { CustomTaskLogger.Print(Loglevel.Success, "任务监控成功开启!"); };
                _currengWebsocket.Error += (s, arg) => { CustomTaskLogger.Print(arg.Exception, "任务监控出现未知错误!"); };
                _currengWebsocket.Closed += (s, arg) => { CustomTaskLogger.Print(Loglevel.Warn, "任务监控已关闭!"); };
                _currengWebsocket.MessageReceived += (s, arg) =>
                {
                    if (arg.Message.IsNotNullOrEmpty())
                    {
                        var message = JsonConvert.DeserializeObject<SocketMessage>(arg.Message);

                        #region STARTTASK

                        if (message.MessageType.ToUpper() == "STARTTASK" || message.MessageType.ToUpper() == "STOPTASK")
                            try
                            {
                                var taskConmmandEntity =
                                    JsonConvert.DeserializeObject<TaskConmmandEntity>(message.Data);
                                if (taskConmmandEntity != null && taskConmmandEntity.CommandId.IsNotNullOrEmpty() &&
                                    taskConmmandEntity.Commandstate == 0)
                                    if (taskConmmandEntity.NodeId == ZilLionConfigurationManager
                                            .GetConfigInstance<TaskManagerCommonConfig>().ClientNo)
                                        RunCommond(taskConmmandEntity);
                            }
                            catch (Exception e)
                            {
                                CustomTaskLogger.Print(e, $"处理任务{message.MessageId}出现错误!");
                            }

                        #endregion
                    }
                };
                _currengWebsocket.Open();
            }
        }

        /// <summary>
        ///     运行处理循环
        /// </summary>
        public static void Run()
        {
            Running();
            CustomTaskLogger.GetWebSocket();
            InitSocketClient();
        }

        public static void Stop()
        {
            _currengWebsocket.Close();
        }

        private static void Running()
        {
            RecoveryStartTasks();
            Thread.Sleep(2000);
            RununHandleCommands();
        }


        /// <summary>
        ///     恢复已开启的任务
        /// </summary>
        private static void RecoveryStartTasks()
        {
            #region 开启需要开启的任务

            try
            {
                CustomTaskLogger.Print(Loglevel.Success, "当前节点启动成功,准备恢复已经开启的任务...");
                var response = TaskStateRespository.GetAllTaskState(ZilLionConfigurationManager
                    .GetConfigInstance<TaskManagerCommonConfig>().ClientNo);
                var taskStates = new List<TaskStateEntity>();
                if (response?.TaskStates != null)
                    taskStates.AddRange(response.TaskStates.Where(x => x.Taskstatus == 0));

                var successCount = 0;
                foreach (var runlog in taskStates)
                    try
                    {
                        CommandFactory.Execute(new TaskConmmandEntity
                        {
                            CommandUpdateTime = DateTime.Now,
                            Commandname = EnumTaskCommandName.StartTask.ToString(),
                            Commandstate = (short) EnumTaskCommandState.None,
                            NodeId = ZilLionConfigurationManager.GetConfigInstance<TaskManagerCommonConfig>().ClientNo,
                            Taskid = runlog.Taskid,
                            CommandId = string.Empty
                        });
                        successCount++;
                    }
                    catch (Exception ex)
                    {
                        CustomTaskLogger.Print(ex, $"恢复任务{runlog.Taskid}失败!");
                    }

                CustomTaskLogger.Print(Loglevel.Success,
                    $"恢复已经开启的任务完毕，共{taskStates.Count}条任务,其中{successCount}条重启成功,{taskStates.Count - successCount}条重启失败");
            }
            catch (Exception exp)
            {
                CustomTaskLogger.Print(exp, "执行命令");
            }

            #endregion
        }


        private static void RununHandleCommands()
        {
            try
            {
                var unHandleCommands = new List<TaskConmmandEntity>();
                var response =
                    TaskCommandRespository.GetUnHandleTaskConmmandEntities(
                        ZilLionConfigurationManager.GetConfigInstance<TaskManagerCommonConfig>().ClientNo);
                if (response?.TaskConmmands != null)
                    unHandleCommands.AddRange(response.TaskConmmands);

                if (unHandleCommands.Any())
                    CustomTaskLogger.Print(Loglevel.Info, "当前节点扫描到" + unHandleCommands.Count() + "条命令,并执行中....");

                foreach (var command in unHandleCommands)
                    RunCommond(command);
            }
            catch (Exception exp)
            {
                CustomTaskLogger.Print(exp, "系统级不可恢复严重错误");
            }
        }

        private static void RunCommond(TaskConmmandEntity command)
        {
            try
            {
                try
                {
                    CustomTaskLogger.Print(Loglevel.Info,
                        $"收到当前节点待执行命令! 命令名:{command.Commandname},命令内容:{command.CommandContent}");
                    CommandFactory.Execute(command);
                }
                catch (Exception ex)
                {
                    CustomTaskLogger.Print(ex, $"ID为{command.CommandId}的命令执行失败!");
                    command.Commandstate = 1;
                    command.CommandUpdateTime = DateTime.Now;
                    TaskCommandRespository.SaveTaskConmmandEntity(command);
                }
                command.Commandstate = 2;
                command.CommandUpdateTime = DateTime.Now;
                TaskStateRespository.ReportCommandExcuted(command);

                CustomTaskLogger.Print(Loglevel.Success,
                    $"当前节点执行命令成功! id:{command.CommandId},命令名:{command.Commandname},命令内容:{command.CommandContent}");
            }
            catch (Exception exp)
            {
                CustomTaskLogger.Print(exp, "系统级不可恢复严重错误");
            }
        }
    }
}